﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Web;
using System.Web.Mvc;
using ChampionsLeagueBets.Domain;
using ChampionsLeagueBets.Domain.Common;
using ChampionsLeagueBets.Infrastructure;
using ChampionsLeagueBets.Web.Mvc.Authentication;
using ChampionsLeagueBets.Web.Mvc.Common;
using ChampionsLeagueBets.Web.Mvc.Controllers.ViewModels;
using MvcContrib;
using SharpArch.NHibernate.Contracts.Repositories;
using SharpArch.NHibernate.Web.Mvc;

namespace ChampionsLeagueBets.Web.Mvc.Controllers
{
	public class InvitationsController : Controller
	{
		/// <summary>
		/// Dostep do bazy danych.
		/// </summary>
		private readonly IExRepository<Invitation> _invitationRepository;

		/// <summary>
		/// Dostep do bazy danych.
		/// </summary>
		private readonly IExRepository<Email> _emailRepository;

		/// <summary>
		/// Dostep do bazy danych.
		/// </summary>
		private readonly IExRepository<User> _userRepository;

		/// <summary>
		/// Dostep do bazy danych.
		/// </summary>
		private readonly IExRepository<InvitedPerson> _invitedPersonRepository;

		public InvitationsController(IExRepository<Invitation> invitationRepository, IExRepository<User> userRepository, IExRepository<Email> emailRepository, IExRepository<InvitedPerson> invitedPersonRepository)
		{
			_invitationRepository = invitationRepository;
			_userRepository = userRepository;
			_emailRepository = emailRepository;
			_invitedPersonRepository = invitedPersonRepository;
		}

		/// <summary>
		/// Usuwanie uzytkownika.
		/// </summary>
		/// <param name="id"></param>
		/// <returns></returns>
		[Transaction]
		public ActionResult Delete(int id)
		{
			if (!RightPrincipal.CurrentUser.IsAdmin) return this.RedirectToAction<HomeController>(c => c.NoRights());

			InvitedPerson invitedPerson = _invitedPersonRepository.Get(id);
			_invitedPersonRepository.Delete(invitedPerson);
			_invitedPersonRepository.DbContext.CommitTransaction();

			//return this.RedirectToAction(c => c.Index());
			return PartialView("_InvitedPersonsList", _invitedPersonRepository.GetAll());
		}

		/// <summary>
		/// Usuwanie uzytkownika.
		/// </summary>
		/// <param name="id"></param>
		/// <returns></returns>
		[Transaction]
		public ActionResult Accept(int id)
		{
			if (!RightPrincipal.CurrentUser.IsAdmin) return this.RedirectToAction<HomeController>(c => c.NoRights());

			InvitedPerson invitedPerson = _invitedPersonRepository.Get(id);
			
			User user = new User();
			user.Email = invitedPerson.Email;
			user.FirstName = invitedPerson.FirstName;
			user.Surname = invitedPerson.Surname;
			user.Password = invitedPerson.Password;
			user.UserName = invitedPerson.UserName;
			user.InvitedPerson = invitedPerson;

			user = _userRepository.SaveOrUpdate(user);
			invitedPerson.User = user;


			Email emailData = new Email();
			emailData.ReceiverAddress = invitedPerson.Email;
			emailData.ReceiverName = invitedPerson.FullName;
			emailData.Subject = "[Bet-at-Work] Aktywacja konta";
			emailData.Body = string.Format("<p>Witaj {0}.</p><p>Twoje konto w systemie zostało aktywowane. Od tej chwili na stronie: <a href='{1}'>{1}</a> możesz typować wyniki turniejów.</p>" +
				"<p><font style='size:0.8em;color:gray;'>Poniższy email został wygenerowany automatycznie, prosimy na niego nie odpowiadać.</font></p>", user.FirstName, SettingManagementService.SystemAddress);


			_userRepository.SaveOrUpdate(user);

			emailData = EmailManager.SendEmail(emailData);
			_emailRepository.SaveOrUpdate(emailData);

			_invitedPersonRepository.DbContext.CommitTransaction();


			//return this.RedirectToAction(c => c.Index());
			return PartialView("_InvitedPersonsList", _invitedPersonRepository.GetAll());
		}

		/// <summary>
		/// Lista uzytkownikow.
		/// </summary>
		/// <returns></returns>
		public ActionResult Index()
		{
			if (!RightPrincipal.CurrentUser.IsAdmin) return this.RedirectToAction<HomeController>(c => c.NoRights());

			var invitedPersons = _invitedPersonRepository.GetAll();
			return View(invitedPersons);
		}

		[HttpPost]
		[Transaction]
		[ValidateAntiForgeryToken]
		public ActionResult Create(string email)
		{
			try
			{
				if (!string.IsNullOrEmpty(email))
				{
					User user = _userRepository.Get(RightPrincipal.CurrentUser.Id);
					Invitation invitation = new Invitation();
					invitation.InvitedEmail = email;
					invitation.CreateDate = DateTime.Now;
					invitation.InvitationGuid = Guid.NewGuid();
					invitation.InvitingUser = user;
					user.Invitations.Add(invitation);


					Email emailData = new Email();
					emailData.ReceiverAddress = email;
					emailData.ReceiverName = email;
					emailData.Subject = "[Bet-at-Work] Zaproszenie";
					emailData.Body = string.Format("<p>Witaj.</p><p>Zostałeś zaproszony przez: {0} do systemu Bet-at-Work. Kliknij poniższy link, aby się w nim zarejestrować: " +
						"<a href='{3}/Invitations/InvitedUserData?guid={1}'>{3}/Invitations/InvitedUserData?guid={2}</a></p>" +
						"<p><font style='size:0.8em;color:gray;'>Poniższy email został wygenerowany automatycznie, prosimy na niego nie odpowiadać.</font></p>", user.FullName, invitation.InvitationGuid, invitation.InvitationGuid, SettingManagementService.SystemAddress);


					_userRepository.SaveOrUpdate(user);

					emailData = EmailManager.SendEmail(emailData);
					_emailRepository.SaveOrUpdate(emailData);

					_invitationRepository.SaveOrUpdate(invitation);
				}

				return new EmptyResult();
			}
			catch
			{
				return new EmptyResult();
			}
		}

		/// <summary>
		/// Użytkownik - wyswietlenie okna do zalogowania
		/// </summary>
		/// <returns>Widok okna logowania</returns>
		public ActionResult InvitedUserData(string guid)
		{
			Guid invitedGuid = new Guid(guid);
			Invitation invitation = _invitationRepository.GetQuery().Where(i => i.InvitationGuid == invitedGuid && i.InvitedPerson == null).FirstOrDefault();

			if(invitation == null)
			{
				return this.RedirectToAction<UsersController>(c => c.Index());
			}

			ViewData["guid"] = guid;
			return View();
		}

		/// <summary>
		/// Tworzenie nowego uzytkownika.
		/// </summary>
		/// <param name="invitedPersonViewModel"></param>
		/// <returns></returns>
		[HttpPost]
		[ValidateAntiForgeryToken]
		[Transaction]
		public ActionResult InvitedUserData(string guid, InvitedPersonViewModel invitedPersonViewModel)
		{
			//if (!RightPrincipal.CurrentUser.IsAdmin) return this.RedirectToAction<HomeController>(c => c.NoRights());

			try
			{
				if (invitedPersonViewModel.InvitedPerson.IsValid())
				{
					using (MD5 md5Hash = MD5.Create())
					{
						invitedPersonViewModel.InvitedPerson.Password = Md5Helper.GetMd5Hash(md5Hash, invitedPersonViewModel.FirstPassword);
					}
					Guid invitedGuid = new Guid(guid);
					Invitation invitation = _invitationRepository.GetQuery().Where(i => i.InvitationGuid == invitedGuid).FirstOrDefault();
					invitedPersonViewModel.InvitedPerson.Invitation = invitation;
					invitation.InvitedPerson = invitedPersonViewModel.InvitedPerson;

					_invitedPersonRepository.SaveOrUpdate(invitedPersonViewModel.InvitedPerson);
				}

				TempData[ActionConfirmation.TempDataKey] = ActionConfirmation.CreateSuccess("Twoje dane zostały zapisane. Musisz poczekać na aktywację konta.");
				return this.RedirectToAction<HomeController>(c => c.Index());
			}
			catch
			{
				TempData[ActionConfirmation.TempDataKey] = ActionConfirmation.CreateError("Błąd podczas zapisu danych.");
				return View();
			}
		}

		/// <summary>
		/// Sprawdzenie czy podany login jest dostepny.
		/// </summary>
		/// <param name="invitedPerson"></param>
		/// <returns></returns>
		public JsonResult UserNameAvailable(InvitedPerson invitedPerson)
		{
			if (invitedPerson == null) throw new ArgumentNullException("invitedPerson");

			// Pobieramy uzytkownika po loginie.
			User u = _userRepository.GetQuery().Where(l => l.UserName == invitedPerson.UserName).FirstOrDefault();

			// Jesli nie ma uzytkownika lub jest to uzytkownik dla ktorego sprawdzamy.
			if (u == null)
			{
				return Json(true, JsonRequestBehavior.AllowGet);
			}
			return Json("Podany login jest zajęty", JsonRequestBehavior.AllowGet);
		}
	}
}
